JavaFX中的javaunicode补充平面
我在处理JavaFX中来自补充(“astral”)平面的Unicode字符时遇到问题。具体地说,我不能在TextInputDialog
中粘贴这样的字符(取而代之的是一些奇怪的字符,例如ð
),也不能在WebView中使用它们(它们被呈现为������
)
如果我通过JOptionPane.showInputDialog
输入相同的字符并将它们打印到控制台,那么这些字符工作得非常好。它们甚至显示在JavaFXAlert
中,尽管它在末尾附加了一些垃圾
有没有办法解决这些问题
我正在Linux中使用Oracle JDK 1.8.051版
补充平面字符示例:😀 𐂃 🂡 🙭 𫞂
如果看不到,可能需要安装其他字体,如Symbola或Noto
下面是一个示例程序(使用Label
而不是WebView
):
import javax.swing.JOptionPane;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TextInputDialog;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class UniTest extends Application {
@Override
public void start(final Stage stage) throws Exception {
final String s = new String(new int[]{127137, 178050, 3232, 128512, 241}, 0, 5);
System.out.println("The string: " + s);
System.out.println("Characters: " + s.length());
System.out.println("Code points: " + s.codePoints().count());
JOptionPane.showMessageDialog(null, s, "JOptionPane", JOptionPane.INFORMATION_MESSAGE);
final Alert al = new Alert(AlertType.INFORMATION);
al.setTitle("Alert");
al.setContentText(s);
al.showAndWait();
final TextInputDialog dlg = new TextInputDialog();
dlg.setTitle("TextInputDialog");
dlg.setContentText("Try to paste the string in here");
dlg.showAndWait().ifPresent(x -> System.out.println("Your input: " + x));
final StackPane root = new StackPane();
root.getChildren().add(new Label(s));
stage.setScene(new Scene(root, 400, 300));
stage.setTitle("Stage");
stage.show();
}
public static void main(final String... args) {
launch(args);
}
}
以下是我得到的结果:
注意:本例中并非所有字符都来自补充平面,其中一个字符仅在控制台中正确呈现
# 1 楼答案
TL;DR:显然JavaFX有缺陷
这是你正在使用的文本
十进制码点表示法:
十六进制表示法:
显示错误
Java在内部使用UTF-16。因此,考虑UTF16表示:
UTF-16代表:
我们可以看到,屏幕上显示的是您期望的五个字符,但随后是三个垃圾字符
因此,它显然试图显示8个字形,其中只有5个。这几乎可以肯定,因为显示代码的计数是8个字符,因为三个字符以UTF-16编码为代理对,所以每个字符有两个16位的字。换句话说,在存在代理项对的情况下,它使用了错误的字符串长度值
粘贴文本错误
UTF-8测试数据的表示:
我们看到的是
(这两个控制字符可以在某些字体中包含包含缩写或十六进制代码的字形。这些在您的示例中可见。)
拉丁1十六进制表示法:
请注意,这五个字节与预期文本的UTF-8表示的前五个字节相同
结论:粘贴的数据被粘贴为5个UTF-8码点,占17字节,但被解释为5个Latin1码点,占5字节。同样,长度使用了错误的属性
# 2 楼答案
这个问题已经在Java10中得到了解决。 见Java Bug Report